use ic_crypto_internal_basic_sig_rsa_pkcs1::*;

#[test]
fn should_be_able_to_parse_rsa_pubkey() {
    let der = hex::decode("308201A2300D06092A864886F70D01010105000382018F003082018A0282018100C3A7390CD127D3DB39DF8B3D944E0FE8B5D61CD0813A3ADA299CFB733847663EEF04A320DC192ED3121966C591A55A92A52FD5B0FCB5FD65FD2D0C107AD175222A8816CD93C818F7705B367971FBD3D7ADC84F2BABED363AF712C7D0FDC995159C50A146B90D683DE604A71E0A5638A80A1E0D2E78EAFE289C9B572E4D492EB89A9C1C33CA54C8A399CC9C98684293E65419027CB87712EAC391FFD03EE41C8804F94931CD21B96C214E308287E8FE9D6DDA2B299A86211503D4B74E4A68E2E38D8179107B0F5200ED6D8C1E4F7D7FC0BC170E559D243CAC84AF34428BB2BD68B848238361FD4EE5A857DB7D5CE29FA090F902D37E01AA8285135BE6716AA09C0D62049A98AE9EF66D916C953A194F50F121BCA02C14CBE9697D345CBABE3C984D28B8A02303D5F2FFA71B29BEAD66DF6CC66387AC8C41F89902676F0D913D8824727C9A9D8A976FF358142A09FBE24324AA9FCBB2AC47FFD15C9BEB37ED3E37B91E7C004C3542B2B64669DCF6850AD2EC9F57605B6CD1701F32531011006AAF0203010001").unwrap();

    let _key = RsaPublicKey::from_der_spki(&der).unwrap();
}

#[test]
fn should_be_able_to_parse_rsa_pubkey_from_components() {
    let n = hex::decode("f214c6550cae299ad12538decc70726089538b4236af396399345c7bb7d92e53f4b5dbc9cffd57509fa91e9feba0d7838487a008853fb8ea96970daee66b5119a38fd7796773930bac05b837031f7f89b5bfd92d2ebde5c5eb0665460bf9477a82e7ca6d86c41a4f74c058890f4e5acbc448bf39dd008e914fbbad2c0eee4aa69adf17d923416400635c1420ba008855ca38dcd48c8373d7a80cc2e1745caa2864f7b28cbef5480a595ab1ee156b32017269595816e6cc4f4ad614fccbb013a9cee17c365f8caa23474d5b97f0f096802b73f042af076c88ff037cd0fc706d2392393a56ed58b4e5dbec844bfb91fb9601c64df10f7349b28950344611904205").unwrap();
    let e = hex::decode("010001").unwrap();

    let expected_der = "30820122300d06092a864886f70d01010105000382010f003082010a0282010100f214c6550cae299ad12538decc70726089538b4236af396399345c7bb7d92e53f4b5dbc9cffd57509fa91e9feba0d7838487a008853fb8ea96970daee66b5119a38fd7796773930bac05b837031f7f89b5bfd92d2ebde5c5eb0665460bf9477a82e7ca6d86c41a4f74c058890f4e5acbc448bf39dd008e914fbbad2c0eee4aa69adf17d923416400635c1420ba008855ca38dcd48c8373d7a80cc2e1745caa2864f7b28cbef5480a595ab1ee156b32017269595816e6cc4f4ad614fccbb013a9cee17c365f8caa23474d5b97f0f096802b73f042af076c88ff037cd0fc706d2392393a56ed58b4e5dbec844bfb91fb9601c64df10f7349b289503446119042050203010001";

    let key = RsaPublicKey::from_components(&e, &n).unwrap();

    assert_eq!(hex::encode(key.as_der()), expected_der);
}

#[test]
fn should_reject_invalid_rsa_pubkey_from_components() {
    let valid_n = hex::decode("f214c6550cae299ad12538decc70726089538b4236af396399345c7bb7d92e53f4b5dbc9cffd57509fa91e9feba0d7838487a008853fb8ea96970daee66b5119a38fd7796773930bac05b837031f7f89b5bfd92d2ebde5c5eb0665460bf9477a82e7ca6d86c41a4f74c058890f4e5acbc448bf39dd008e914fbbad2c0eee4aa69adf17d923416400635c1420ba008855ca38dcd48c8373d7a80cc2e1745caa2864f7b28cbef5480a595ab1ee156b32017269595816e6cc4f4ad614fccbb013a9cee17c365f8caa23474d5b97f0f096802b73f042af076c88ff037cd0fc706d2392393a56ed58b4e5dbec844bfb91fb9601c64df10f7349b28950344611904205").unwrap();
    let valid_e = hex::decode("010001").unwrap();

    let small = hex::decode("E6C32A70B0445F5F62C87FB9F0BA8DDABEC25E9F").unwrap();
    let even = hex::decode("11000A").unwrap();

    assert!(RsaPublicKey::from_components(&even, &valid_n).is_err());
    assert!(RsaPublicKey::from_components(&valid_e, &small).is_err());
}

#[test]
fn should_reject_too_small_rsa_pubkey() {
    // Key is valid, 32 bit modulus
    let der =
        hex::decode("301F300D06092A864886F70D0101010500030E00300B0204724570DF0203010001").unwrap();
    assert!(RsaPublicKey::from_der_spki(&der).is_err());
}

#[test]
fn should_reject_even_exponent_rsa_pubkey() {
    // Key is invalid, exponent is even
    let der = hex::decode("308201A2300D06092A864886F70D01010105000382018F003082018A0282018100A08C0938F57C13FE89664C27B2F8B1D0A5EDDC5EDDA19FD761A46F9DC875054C088D32C24B64AAEFDC06A4158DBD9DF67D1BF739A1ADDB519FBA64EA08DF151DE7F70C321496A5AFCD3FDCC20E07B588227F8025212210B59FA53CAD5F795113CC98DD7B8D81FC0DD178380A60468DA28E8B307E02E2005D3339052E82A544C8FA5AA4572558E46943DDA9EB9D33FFF49AD7CE52E6CF503D6E07B27876CD75849286B4CFB03E0CA89EE46675D877CA4400C8EA4206A5C6DC3765605ED9758292841CBB5B0B0DCF56813AC83B3308363780F595723CB5124233FFC70A52001BFCFEFB5B8A69077B02AB215AAEDAAFD9A6DD2B84E02E65FAA0EDB9D32B285D22750A78D7A593396FAD2E1DC56A6E6DCD12C4E50890A5B370BBAF325BB707B2033A269E7CA91FAAE2DE879E51A73E80A96A4280C2CCE5D74ED419FF7B51F60238DBC282FB1A16284A0FD7BF74CE269BB07E87D4C3DA6AEFD13B52C071892F9C2A890F562C8A215B8C87262AE0553E669DED07FA5428B35433AA454CB68F2C7313490203010000").unwrap();
    assert!(RsaPublicKey::from_der_spki(&der).is_err());
}

#[test]
fn should_reject_even_modulus_rsa_pubkey() {
    // Key is invalid, modulus is even
    let der = hex::decode("308201A2300D06092A864886F70D01010105000382018F003082018A0282018100A08C0938F57C13FE89664C27B2F8B1D0A5EDDC5EDDA19FD761A46F9DC875054C088D32C24B64AAEFDC06A4158DBD9DF67D1BF739A1ADDB519FBA64EA08DF151DE7F70C321496A5AFCD3FDCC20E07B588227F8025212210B59FA53CAD5F795113CC98DD7B8D81FC0DD178380A60468DA28E8B307E02E2005D3339052E82A544C8FA5AA4572558E46943DDA9EB9D33FFF49AD7CE52E6CF503D6E07B27876CD75849286B4CFB03E0CA89EE46675D877CA4400C8EA4206A5C6DC3765605ED9758292841CBB5B0B0DCF56813AC83B3308363780F595723CB5124233FFC70A52001BFCFEFB5B8A69077B02AB215AAEDAAFD9A6DD2B84E02E65FAA0EDB9D32B285D22750A78D7A593396FAD2E1DC56A6E6DCD12C4E50890A5B370BBAF325BB707B2033A269E7CA91FAAE2DE879E51A73E80A96A4280C2CCE5D74ED419FF7B51F60238DBC282FB1A16284A0FD7BF74CE269BB07E87D4C3DA6AEFD13B52C071892F9C2A890F562C8A215B8C87262AE0553E669DED07FA5428B35433AA454CB68F2C7313480203010001").unwrap();
    assert!(RsaPublicKey::from_der_spki(&der).is_err());
}

#[test]
fn should_reject_too_large_rsa_pubkey() {
    // Key is valid, 16000 bit modulus
    let der = hex::decode("308207F2300D06092A864886F70D0101010500038207DF00308207DA028207D100AD438A7B69410366631C71C14BE8838C607CE237A358586EA38479A025DF569330FE72AD0875B9D6C36F185416268E7681A401C32561F8015F010989F979FA9F3255A830CCF3F7119E4D2796DF098738A12333474EDF77BC36D8E84BD0B1A612F70CA0129556DA56CCB18E374F1F04B23609B452A50B87CF8426812BA20FFEDFF533B6B29B364CF13495503BB8B7C49B5675A295B010922B7D147BA0B8AEBBD279BF0FA47FE538CE088CD7BBA131D1F5AC4C6C8184A6CCC13932A47BA19822C8A87053EAEB77A28322B75C02C65E05A4F1088BED40D39B0D8600888A4864DF680FAF653A1FD15E51887F54F88D5EF6D35795108C867D7B42B48DCEC79EE893B42E54BBE945737AD53D6F8DD654D3D946C84F0B17F68AA81811AEBB18971F2A9EDF829729884216D912A00A1DE946F77414EEDDD4BF47270A7ACFAA55573C6E3ECF290D4A8239F152A1FABEF19EEC31B07E5AE3B05DB00F19BC8BE9BEFE13D5812E0ED42AD3C0A5A2F4632C2BADAC93382ABF5074A09DE91FBD6649EE84E3EF41E195CE470FE9A101F106549473D21E01E85152BE0B0C72A0741FDB521BAB697D19816868D18DD5AC638B4DA184F6E4B5817152F1A472A92DA800A61BEA1FB59BE20ACE9EC1F90905914284801D23D5E1E8E84A55B35554D14023827E4F8CB9CD05A67DC47B66BD29DF6B494711C86444FE6E4575FCD6E0527377A0DBDB1E72A997E4B14BE6CE72DC0A009E3A972F3BC4C0AB5D388FED46E4DA62AF3F15CDC880BEF07E1F031EE538615FC194B44BA863B95A848E41CE362904F0C7AF5C198C95134C0748791623981C2CC718100602C3A6B033E513902E0D4736A62C57B66F079E79134DBC330C5885A8E60870C7AE82A180779BDFD6C7FC0975818F42C86B0DD065D5859EE89000C24ACF02E9B81822445CD1899A064254B69F8885BA18D9E4D5C925B9D5C6E62D587DDF67980D3EAB97A9764F0B8E2BE20DABB6E6CAF97584489CE2E964FA6FC273095C3C0C8169A568C6D096190DC87E1F01C2A41BE09865E8757823BE47B5796D2C2CEF63E0C95141009E23A975629DABDBC64A6F0108C0EC4CC8ADD982BABB1B76C43AB41887D4A7BF7E0B85BFB4BF159CBD89CD6F7C2048487BC3ABB40A72DA6B9BA258A831CCCE0645B0CB25D6ABB788DC2FEB108D002F05AC26A76D2D1EC59FD23C405A5E9C95E2E2B2C53C8D765FA909251E53B3413112CE03285A816324239AECB0A6513362D28FC1D3AD8E9C8BF168520DE7828BD336914C8448714BF76560A6C6A83AED70FCDF65F0FCADBC78625FDA67787D393DFE12300A6B3A67C2B6BA6D586A8657FC8B558E2D8598C6EDE94E1E489C22CC0FF7882515A6222C7D135FDB17C3FF347D21865A2FCCFC8B9C21D1AE5948C51F460ABBF32E017CF8C17C43A3751F8E51607D9DEAB267C4F6099F8F424E91CA3148BFF7F319C40DC6AA1F6B56EC2E032D6F454A777D06D16C8843AEC9505C9880FCBAB904042C05A84AA3C4E2F8C61458A45A7BCA1A6AF08A1E89B7D79248AC89303999DBD447FF59F247F5AB0E984EA605FBD56A8D6AFD1E58B92C32B09B3F10713DE405A971BF90303D64349AECA5709E5C46C610E118AD7F5826E7685FF14732EF9CDC2D8DE69E68CDEFC5CB4C1B113252D3EB552836CDF92950F1AB33EF9697567036CAFBB8953D164B7E285F26B1E6CBDF9095552598D3B2E9F90F46252B3BB017334152BDF396D92D79B74F553459CF68B528C0448C38018966DC5E342230E10A50D460C340D73E2302274208EC114CAC73933EEDBC4300D6DD49BB14FFDB9A79BA106C68BE9B23DDB1B735FA01367E331292A371BD6E4A59F2CAAC204BB8431D8C961E45810BAED39410857DCD027CDF41C272D43385EAA2A6CB307D03F892C6D90EDBE651D5A0757077500707E5C48CC6CD8B0F70CBD5B422F4860B41FC07708A1B1D45198AF0CA648B2DC9045588E858297783D0612CB81B9E6818E5C617DB42597AD867096C1AE468F2CA2CA85E49397DAFD4B690F086CD694670131CCBC799EB5E5D975B1FE1674A6505FD7C1D9DE36F81A26FD127850D7D9D2B9CA51BF999A2CB890212C0F538FA40A836FEE56EAADD5FC29BC8508C529D08D534AFF98FA41BD7A6E2369C12C08BF0E5F7C54070CBD2050E227B021CEF5B38C8B714DE2654FF3EE592B313782628AC1BD8F72F25694721A9ED507E48C3266CE0B8CBB532B76EA31B978C5B7F519845DD48A904A23C45CB52863D6187F9DAEE552375CE48B055CD2AFB8B5353279229E1B03D8FC0533DD735C51557D9708E55CE33320A3252157FAE847C194705C441DA91D70A6C48D1AAD650008821923164A4FD88A4C661B84DBD9BD1A1E6259CAB552FEB5AF23870E3E7965829C4871643205CA5004C604349DCC04EB2E6C1E0B50AAA4B6F8F6B0D935BE73098DC026B1CB6F92C35692D594CE3A2CA5293CC37B768F45D1E3D6561486F016214E0C8A4200C46B0D627E8FE6BAF202DE2750943FBD45EFD86116D35E9E626F48813684EE5DF5689C4C66EC0DB8DAAD1D50A4BA061D7735270E8C665E4514AE646580F118535B03115935C455561069B7E02D2CE31E1017B14D39E75C238B102942A6DA342D1E227852CE032F61EB7CC6ECF827E7266D8537FD1725EAA5AF9198D64DF860F9058081D00965F5E4D78FA4E680C4D64898EAD271A47917CE582E025F1162C6260E22C5F47F3DD51BFB3C5EAE7C3B9EE12E9C61C2E029B5837C270C04A4DDF87F3216C128A8D7D6B8CF4D09C4BA485DF0899CBAECE2F461E4F492E07DE0BCC3EA70AAD9190B14F06BF124AB79CCEC503F70D0203010001").unwrap();
    assert!(RsaPublicKey::from_der_spki(&der).is_err());
}

#[test]
fn should_be_able_to_verify_rsa_signature() {
    let der = hex::decode("30820122300D06092A864886F70D01010105000382010F003082010A0282010100A7078A1A8FDE64C537AE5CA8D4B3A9139D68050CF76E45E77DBE47CECEB162F7095ADB6260998775203AA42A444F865DEB995C2B70B548ECEE01695DEB069ED18744C12FD24AEACDA4B2B7A5E97E7167CAF7D4B8904CE20CA9A8928978CA957FF2D9FCAE0859618B0AD74C164FAF5AB1DE7D7228A89BD3F8B497CEF9E45E1203CC40EE252140157C331A584F3916E569A8C39573D542A3577FB12332EBD3C9F421C9EF8A23D5ACF6BA439F7C3D6B73BA4E56B9B8EFBC42A2E5E734B99FDF7AB046813E43C65C926793919A7AE54F71AAF57C6876001A0558BC847D7555B1AE71F56A70272D786BE69A23A21A56C426371BD9882D40E7ECA6B7DA5D8169B7030F0203010001").unwrap();
    let key = RsaPublicKey::from_der_spki(&der).unwrap();

    let sig = hex::decode("7416E0A20E46CEF9FC09FA87D4C324502839EB8DEAFEF7CA5ADEC1044523232E66B32F4A497AA84FC4069182AD4A921B43DBCBD3ACCA870F887299692E23555086169F89EA1DD4856DC9FEB4E96B1661F803B784B4BE9A0E36B739A38126996912D92343688DB58F24CF8066250E2B04EE166A1C9C924D1AA9DED87D8A24E07CF35B02CA487B1632BA2508FF2B28F880983926A75D67EB83292BF77EE9B283337D841F04253C846BD66E63E50D8B326DCE1EC67A95A9D31DBDF3DCA5E8C09CA8CCE2026A3A5AE56250EC57CDE67A745FA1B1CC83473BA167AD1F8311A3D071184D03380B80C7921457CE282B9222FE805E506B53C5F798917B1A45044D2E896D").unwrap();
    let msg = hex::decode("616263").unwrap();

    assert!(key.verify_pkcs1_sha256(&msg, &sig).is_ok());

    // Wrong message fails to verify
    let msg = hex::decode("6162").unwrap();
    assert!(key.verify_pkcs1_sha256(&msg, &sig).is_err());
}

#[test]
fn should_reject_valid_rsa_signature_with_extra_zeros() {
    let der = hex::decode("30820122300D06092A864886F70D01010105000382010F003082010A0282010100A7078A1A8FDE64C537AE5CA8D4B3A9139D68050CF76E45E77DBE47CECEB162F7095ADB6260998775203AA42A444F865DEB995C2B70B548ECEE01695DEB069ED18744C12FD24AEACDA4B2B7A5E97E7167CAF7D4B8904CE20CA9A8928978CA957FF2D9FCAE0859618B0AD74C164FAF5AB1DE7D7228A89BD3F8B497CEF9E45E1203CC40EE252140157C331A584F3916E569A8C39573D542A3577FB12332EBD3C9F421C9EF8A23D5ACF6BA439F7C3D6B73BA4E56B9B8EFBC42A2E5E734B99FDF7AB046813E43C65C926793919A7AE54F71AAF57C6876001A0558BC847D7555B1AE71F56A70272D786BE69A23A21A56C426371BD9882D40E7ECA6B7DA5D8169B7030F0203010001").unwrap();
    let key = RsaPublicKey::from_der_spki(&der).unwrap();

    let sig = hex::decode("0000000000000000007416E0A20E46CEF9FC09FA87D4C324502839EB8DEAFEF7CA5ADEC1044523232E66B32F4A497AA84FC4069182AD4A921B43DBCBD3ACCA870F887299692E23555086169F89EA1DD4856DC9FEB4E96B1661F803B784B4BE9A0E36B739A38126996912D92343688DB58F24CF8066250E2B04EE166A1C9C924D1AA9DED87D8A24E07CF35B02CA487B1632BA2508FF2B28F880983926A75D67EB83292BF77EE9B283337D841F04253C846BD66E63E50D8B326DCE1EC67A95A9D31DBDF3DCA5E8C09CA8CCE2026A3A5AE56250EC57CDE67A745FA1B1CC83473BA167AD1F8311A3D071184D03380B80C7921457CE282B9222FE805E506B53C5F798917B1A45044D2E896D").unwrap();
    let msg = hex::decode("616263").unwrap();

    assert!(key.verify_pkcs1_sha256(&msg, &sig).is_err());
}

#[test]
fn should_reject_valid_rsa_signature_with_signature_greater_than_modulus() {
    let der = hex::decode("30820122300D06092A864886F70D01010105000382010F003082010A02820101009D698E1ECBFDDF304B77CE796A1AED1078CB15688510BEE181C622A674131176DD89B0E594C3B8E8934793952A22B36B428389F0902809A45278D52371A6299C7B1966C29AD1E2F221AC5ABB25B3C09810FDA816F9F38652C1DCD5D439764454D1CBF7C5E7D2AB4092134A010EC69C8BBCA7C32D8C6FC4888C37F86595124C99D38321C5C73E03180660617311A01D7759A64339CF285C0C0CF0026ECD79C00B141E640E62924B88CF7038713FFB25E8DB7E61306D781C35C4AF70EF3EEF5013A1D50D6180B7DE5D717642A3293B59AB78CA988D0F7493848734425419B47BA3CC1041E45D9370844FC2CAFC0A7E28400D33B338CD74B8BF74980064F9CD77750203010001").unwrap();
    let key = RsaPublicKey::from_der_spki(&der).unwrap();

    let msg = hex::decode("68656C6C6F").unwrap();

    // First check the valid signature
    let sig = hex::decode("09F17E7A37E0485152670F35F78718EF46285D3CA9C03EFEDEACB81CC3322B50647D750581497AC2A6B6B2A408903B54EBCE5531104F6FDA50504E88EDA03786EB43A063A496BA68BEE192E820EACC08A731BEB33B945E81729077E9BBE8E2362CE97F19C3F9D06B326AC5004B3E8326FCF434206DFDDB37FA84F21C9E019BE94649BAAAFDAC3A4C7F060EBDB3DBB08DF13201A3B573632BB083F8E1B726232F52DD1E628C9F58A18D31535FD099EEE7384F2078004B2FDFD8A0FFE2BE457BD32502E5F8668FA6F3545ED82D00D6EAE656CF7BAED73F80938D0826D3B4C3586A9DF72B10908FE0AF8F44D41D05B676AEABF85A8A0C61E9784D50B921606601DE").unwrap();

    assert!(key.verify_pkcs1_sha256(&msg, &sig).is_ok());

    // Now try to verify sig + modulus, which should fail:

    let sig_plus = hex::decode("a75b0c9903de27819ddeddaf61a205ffbef372a52ed0fde06072dac337453cc7420725eb160d33ab39fe463932b2eec02e51df21a077797ea2c923ac5f466123665d07263f689d5ae08deda3469e8ca0b82f66ca3587e4d4346d4dbdf55f268afeb576dfabcc7babc47e0f015a051fb2b99bf74dfa6d9fc086bcea823313e88319ccdc70c4ea3d6485667030c57bce054ad844dd849bbf37bd73fb50849fe33a66fb8270ef31a42a5ca18bd1109514d013cd81a86dc34c159d5070d1fd34cbe6c6d7f359e7478550c5d51ad02a124491cf9a143be6b41418143c6927ce77d40e6a076cf4ee235133df079f1910349eeeb92c0dc2d9d6a237c1e8b9865a337953").unwrap();

    // Verify that we are not hitting the check that the signatures are of unexpected length:
    assert_eq!(sig.len(), sig_plus.len());

    // Verify that signatures greater than the modulus are rejected:
    assert!(key.verify_pkcs1_sha256(&msg, &sig_plus).is_err());
}

#[test]
fn should_be_able_to_serialize_and_deserialize_rsa_pubkey() {
    let der = hex::decode("30820122300D06092A864886F70D01010105000382010F003082010A0282010100A7078A1A8FDE64C537AE5CA8D4B3A9139D68050CF76E45E77DBE47CECEB162F7095ADB6260998775203AA42A444F865DEB995C2B70B548ECEE01695DEB069ED18744C12FD24AEACDA4B2B7A5E97E7167CAF7D4B8904CE20CA9A8928978CA957FF2D9FCAE0859618B0AD74C164FAF5AB1DE7D7228A89BD3F8B497CEF9E45E1203CC40EE252140157C331A584F3916E569A8C39573D542A3577FB12332EBD3C9F421C9EF8A23D5ACF6BA439F7C3D6B73BA4E56B9B8EFBC42A2E5E734B99FDF7AB046813E43C65C926793919A7AE54F71AAF57C6876001A0558BC847D7555B1AE71F56A70272D786BE69A23A21A56C426371BD9882D40E7ECA6B7DA5D8169B7030F0203010001").unwrap();
    let key = RsaPublicKey::from_der_spki(&der).unwrap();

    let json = serde_json::to_string(&key).unwrap();

    let deserialized: RsaPublicKey = serde_json::from_str(&json).unwrap();

    assert_eq!(key, deserialized);
}
